package com.itguigu.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;

/**
 * 目标:
 * 定义四个方法 获取目标方法信息 返回值 异常对象
 */
//@Component
//@Aspect
public class MyAspect {

    /**
     * 1.定义方法 --增强代码
     * 2.使用注解指定对应位置
     * 3.配置切点表达式选中方法
     * 4.切面和ioc配置
     * 5.开启aspectj自动代理
     * <p>
     * TODO: 增强方法中获取目标信息方法
     *      1.全部增强方法中 获取目标方法的信息（ 方法名 参数 访问修饰符 所属类信息）
     *      （JoinPoint joinPoint）
     *       joinpoint中包含目标方法的信息
     *      2.获取目标方法的返回值 -@AfterReturning
     *      （returning = "result"）result接收返回结果
     *       @AfterReturning(value = "execution(* com..impl.*.*(..))" ,returning = "形参名")
     *      3.获取目标方法的异常对象 -@AfterThrowing
     *      （throwing = "e"）e接收异常对象
     *       @AfterThrowing(value = "execution(* com..impl.*.*(..))",throwing = "形参名")
     */

    @Before("execution(* com..impl.*.*(..))")
    public void before(JoinPoint joinPoint) {
        // 1.通过JoinPoint对象获取目标方法签名对象
        // 方法的签名：一个方法的全部声明信息
        Signature signature = joinPoint.getSignature();

        // 2.通过方法的签名对象获取目标方法的详细信息
        String methodName = signature.getName();// 方法名
        System.out.println("methodName = " + methodName);

        int modifiers = signature.getModifiers();// 访问修饰符
        String modifier = Modifier.toString(modifiers);
        System.out.println("modifiers = " + modifier);

        String declaringTypeName = signature.getDeclaringTypeName();// 所属类信息
        System.out.println("declaringTypeName = " + declaringTypeName);

        // 3.通过JoinPoint对象获取外界调用目标方法时传入的实参列表
        Object[] args = joinPoint.getArgs();

        // 4.由于数组直接打印看不到具体数据，所以转换为List集合
        List<Object> argList = Arrays.asList(args);

        System.out.println("[AOP前置通知] " + methodName + "方法开始了，参数列表：" + argList);
    }

    @AfterReturning(value = "execution(* com..impl.*.*(..))", returning = "result")
    public void afterReturning(Object result) {

        System.out.println("[AOP后置通知] 方法返回，返回结果：" + result);
    }

    @AfterThrowing(value = "execution(* com..impl.*.*(..))", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e) {

        String methodName = joinPoint.getSignature().getName();// 方法名
        System.out.println("[AOP异常通知] " + methodName + "方法抛异常了，异常类型是：" + e.getClass().getName());
    }

    @After("execution(* com..impl.*.*(..))")
    public void after() {
        System.out.println("[日志] 最终通知");
    }

}
